﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using Hack.Extensions;
namespace ConsoleApplication1
{
    public class TheNeverHoodBLB
    {
        public struct BLBHeader
        {
            [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4)]
            public string szID;
            public byte bID;
            public byte bUnknown;
            public uint wDataSize;
            public uint dwFileSize;
            public uint dwNumber;
        };
        public struct BLBDirEntry
        {
            public byte bType;
            public byte bAction;
            public uint wDataIndex;
            public uint dwUnknown;
            public uint dwStart;
            public uint dwFileID;
            public uint dwOutSize;
        }
        public enum bType : byte
        {
            /// <summary>
            /// sound effect file
            /// </summary>
            SoundEffect = 0x07,
            /// <summary>
            /// music file
            /// </summary>
            Music = 0x08,
            /// <summary>
            /// video file (SMK -- Smacker video, www.smacker.com)
            /// </summary>
            VideoFile = 0x0A
        };
        public enum bAction : byte
        {
            /// <summary>
            /// none: the file is non-compressed, no additional actions are required
            /// </summary>
            NonCompressed = 0x01,
            /// <summary>
            /// decompress: the file is PKWARE-compressed (see below)
            /// </summary>
            /*
                // decompression function -- returns zero on success
                DWORD (__cdecl *Uncompress)
                (
                 char	*outputBuffer,
                 DWORD *pOutSize,
                 char	*inputBuffer,
                 DWORD  dwSize
                );

                // first, load the library
                HINSTANCE hDllInst=LoadLibrary("pkware.dll");

                // get the decompression function address
                Uncompress=(DWORD (__cdecl *)(char*, DWORD*, char*, DWORD))GetProcAddress(hDllInst,"Uncompress");

                // decompress file -- it's assumed here that input buffer contains compressed
                // file loaded from BLB archive and output buffer is allocated and has proper
                // size (that is, (dwOutSize) value from the corresponding directory entry)
                Uncompress(outputBuffer,&dwOutSize,inputBuffer,dwSize);

                // now (outputBuffer) contains decompressed file and (dwOutSize) is set to
                // decompressed file size (you should use directory entry value of output
                // size for output buffer allocation)
            */
            Decompress = 0x03,
            /// <summary>
            /// fake: the file is fake, that is no file is really present (see below)
            /// </summary>
            Fake = 0x65
        }
        public void Begin()
        {
            string blbDir = @"C:\Windows.old\Program Files\DreamWorks Interactive\Neverhood\HD.BLB";

            BLBHeader aStruct;
            int count = Marshal.SizeOf(typeof(BLBHeader));
            byte[] readBuffer = new byte[count];
            BinaryReader reader = new BinaryReader(File.Open(blbDir, FileMode.Open));
            readBuffer = reader.ReadBytes(count);
            GCHandle handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
            aStruct = (BLBHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BLBHeader));
            handle.Free();
            reader.Close();

            Debugger.Break();
//            var items = str(blbDir,aStruct.dwNumber);
//            items.ForEach<BLBDirEntry>((dir) =>
//                {
//                    Console.WriteLine(String.Format(
//@"File: 
//    Action: {0} 
//    Type: {1} 
//    FileID: {2} 
//    OutSize: {3} 
//    Start: {4} 
//    DataIndex: {5} 
//    Unknown: {6}
//
//    ",
//                    dir.bAction, 
//                    dir.bType, 
//                    dir.dwFileID,
//                    dir.dwOutSize, 
//                    dir.dwStart, 
//                    dir.wDataIndex, 
//                    dir.dwUnknown)
//                    );
//                });
            //BLBHeader aStruct;
            //int count = Marshal.SizeOf(typeof(BLBHeader));
            //byte[] readBuffer = new byte[count];
            //BinaryReader reader = new BinaryReader(File.Open(blbDir, FileMode.Open));
            //readBuffer = reader.ReadBytes(count);
            //GCHandle handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
            //aStruct = (BLBHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BLBHeader));
            //handle.Free();
            //Debugger.Break();
            //reader.Close();

        }
        public BLBDirEntry[] str(string blbDir, uint _count)
        {
            BLBDirEntry[] ret = new BLBDirEntry[_count];
            BLBDirEntry aStruct;
            int count = Marshal.SizeOf(typeof(BLBDirEntry));
            byte[] readBuffer = new byte[count];
            BinaryReader reader = new BinaryReader(File.Open(blbDir, FileMode.Open));
            for (int i = 0; i < _count; i++)
            {
                readBuffer = reader.ReadBytes(count);
                GCHandle handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
                aStruct = (BLBDirEntry)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BLBDirEntry));
                handle.Free();

                ret[i] = aStruct;
            }
            reader.Close();

            return ret;
        }
    }
}
//public struct BLBHeader
//{
// char	szID[4];
// byte	bID;
// byte	bUnknown;
// uint	wDataSize;
// uint dwFileSize;
// uint dwNumber;
//};